package org.iogame.socket;

import cn.hutool.json.JSONUtil;
import com.iohao.game.action.skeleton.core.CmdKit;
import com.iohao.game.action.skeleton.core.DevConfig;
import com.iohao.game.bolt.broker.client.external.bootstrap.ExternalKit;
import com.iohao.game.bolt.broker.client.external.bootstrap.message.ExternalMessage;
import com.iohao.game.common.kit.ProtoKit;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.iogame.controller.SocketServer;
import org.iogame.data.DataMap;
import org.iogame.dto.Result;
import org.iogame.util.JsonUtil;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.enums.ReadyState;

import java.util.HashMap;

/**
 * @author lc
 * @since 2022/10/1
 */
@Slf4j
public class IoGameSocket {

    /**
     * 保存与io game的连接
     */
    public static HashMap<String, WebSocketClient> socketMap = new HashMap<>();

    @SneakyThrows
    public static void connect(String wsUrl, String userId) {
        WebSocketClient v = socketMap.get(userId);
        if (v == null) {
            DefaultWebSocketClient defaultSocket = DefaultWebSocketClient.newMe(wsUrl);
            defaultSocket.addCallback(DefaultWebSocketClient.Status.OPEN, (Open) han -> {

                //连接成功加入服务器
                socketMap.put(userId, defaultSocket);

                SocketServer.sendByUserIdMessage(Result.buildResult(VueRouter.CONNECT, 0), userId);
                SocketServer.sendAllMessage(Result.buildResult(VueRouter.SOCKET_COUNT, socketMap.size()));
            });

            defaultSocket.addCallback(DefaultWebSocketClient.Status.CLOSE, (Close) (code, reason, remote) -> {
                SocketServer.sendAllMessage(Result.buildResult(VueRouter.SOCKET_COUNT, socketMap.size()));
            });

            defaultSocket.addCallback(DefaultWebSocketClient.Status.ERROR, (Error) (ex) -> {
                SocketServer.sendByUserIdMessage(Result.buildResult(VueRouter.CONNECT, -2), userId);

                // 返回连接io game的连接数
                SocketServer.sendAllMessage(Result.buildResult(VueRouter.SOCKET_COUNT, socketMap.size()));
            });

            defaultSocket.addCallback(DefaultWebSocketClient.Status.MESSAGE, (Message) (byteBuffer) -> {
                // 接收服务器返回的消息
                byte[] dataContent = byteBuffer.array();
                ExternalMessage message = ProtoKit.parseProtoByte(dataContent, ExternalMessage.class);

                if (message.getResponseStatus() != 0) {
                    SocketServer.sendByUserIdMessage(Result.buildResult(VueRouter.MSG, JsonUtil.toJson(message)), userId);
                    return;
                }
                // 之前的
                //log.info("命令map: {}", DataMap.MERGE_MAP);
                try {
                    Object v1 = DataMap.MERGE_MAP.get(message.getCmdMerge());
                    if (v1 == null) {
                      v1 = DevConfig.me().getCmdDataClassMap().get(message.getCmdMerge())
                              .getDeclaredConstructor().newInstance();
                    }
                    Object o = ProtoKit.parseProtoByte(message.getData(), v1.getClass());
                    log.info("收到数据: {}", o);
                    // 调整成json转发回去
                    SocketServer.sendByUserIdMessage(Result.buildResult(VueRouter.MSG, JsonUtil.toJson(o)), userId);
                } catch (Exception e) {
                    HashMap<String, Object> map = new HashMap<>();
                    map.put("映射出错:", e.getMessage());
                    SocketServer.sendByUserIdMessage(Result.buildResult(VueRouter.MSG, JsonUtil.toJson(map)), userId);
                }

            });

            // 开始连接服务器
            defaultSocket.connect();

            return;
        }
        if (v.getReadyState() == ReadyState.OPEN) {
            v.close();
            socketMap.remove(userId);
        }

    }


    /**
     * 获取封装好的消息体
     *
     * @since 2022/10/1
     */
    public static byte[] getMessage(int cmdMerge, Object obj) {
        ExternalMessage externalMessage = ExternalKit.createExternalMessage(CmdKit.getCmd(cmdMerge)
                , CmdKit.getSubCmd(cmdMerge), obj);
        return ProtoKit.toBytes(externalMessage);
    }

    /**
     * 发送消息
     *
     * @since 2022/10/12
     */
    public static void send(String key, String json, String userId) {
        Integer router = DataMap.ROUTER_MAP.get(key);
        if (router == null) {
            log.info("路由地图： {}", DataMap.ROUTER_MAP);
            SocketServer.sendByUserIdMessage(Result.buildResult(VueRouter.ERROR, "找不到路由地图"), userId);
            return;
        }
        WebSocketClient client = socketMap.get(userId);
        if (client == null) {
            SocketServer.sendByUserIdMessage(Result.buildResult(VueRouter.ERROR, "找不到IoGame连接"), userId);
            return;
        }

        Object o = DataMap.PARAM_MAP.get(key);

        // 判断前端是不是json
        if (json != null && JSONUtil.isTypeJSON(json)) {
            // 传送到里面去
            try {
                JsonUtil.toObj(json, o);
            } catch (Exception e) {
                HashMap<String, Object> map = new HashMap<>();
                map.put("异常错误", e.getMessage());
                SocketServer.sendByUserIdMessage(Result.buildResult(VueRouter.MSG, JsonUtil.toJson(map)), userId);

                e.printStackTrace();
                throw new RuntimeException(e);
            }
        } else {
            // 这里必须设置null否则字符串，底层无法正确解析proto
            o = null;
        }
        byte[] message = getMessage(router, o);
        client.send(message);

    }

    public static void close(String userId) {
        WebSocketClient client = socketMap.get(userId);
        if (client != null) {
            client.close();
            socketMap.remove(userId);
        }
    }
}
